package com.kdzy.lshy.socity_server.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.kdzy.lshy.socity_server.common.*;
import com.kdzy.lshy.socity_server.common.wechart.SignatureUtil;
import com.kdzy.lshy.socity_server.common.wechart.VisitUrl;
import com.kdzy.lshy.socity_server.common.wechart.WechartCommon;
import com.kdzy.lshy.socity_server.repository.BaseDao;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.support.StandardMultipartHttpServletRequest;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;

import static com.kdzy.lshy.socity_server.common.wechart.WXCore.decrypt;

/**
 * 微信小程序service
 * @author cly
 * @since 2018-06-21
 */
@Service
public class WechartService extends BaseService {

    private static final Logger logger = LoggerFactory.getLogger(WechartService.class);

    @Resource
    private BaseDao baseDao;

    @Autowired
    private QiNiu qiNiu;

    /**
     * 微信小程序 - 验证是否注册（认证）
     * @param param 包含临时登录code，用来换取用户的openid和session_key、unionid 等信息
     * @return 结果集 - 是否需要弹出登录或者注册窗口
     */
    public Object wechartLogin(String param, HttpServletRequest request) {
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer version = jsonObject.getInteger("version"); // 版本 0:测试 1:生产
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否有效 0:有效 1:无效

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (version == null) {
                    logger.info("参数version为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String createTime = DateUtil.format(new Date(stamp), "yyyy-MM-dd HH:mm:dd"); // 更新时间yyyy-MM-dd HH:mm:ss

                if (visitPlat == 2) { // 小程序
                    String code = (String)jsonObject.get("code"); // 临时登录code

                    if (!StringUtils.isNoneBlank(StringUtils.trim(code))) { // code为空
                        logger.info("临时登录code为空");
                        map = ResultMap.creatReault("88", "失败", "参数为空");
                        logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    // 封装微信个人基本信息
                    Map<String, Object> baseInfoMap = null;

                    logger.info("根据code向微信服务器请求的地址：" + String.format(WechartCommon.GET_USER_INFO_URL, WechartCommon.APPID, WechartCommon.SECRET, code));
                    // 向微信服务器发送Https请求，根据临时登录code获取用户信息
                    String resultJson = VisitUrl.sendHttps(String.format(WechartCommon.GET_USER_INFO_URL, WechartCommon.APPID, WechartCommon.SECRET, code), null);

                    // 解析返回的json结果
                    JSONObject openIdRes = JSON.parseObject(resultJson);
                    if (openIdRes == null) {
                        logger.error("通过code向微信换取openid失败");
                        map = ResultMap.creatReault("12", "失败", "通过code向微信换取openid失败");
                        logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    if (openIdRes != null) {
                        // 获取状态码
                        Object errcode = jsonObject.get("errcode");
                        if (errcode != null) { // 获取openid失败
                            logger.error("通过临时登录code：" + code + " 获取用户信息失败。errcode：" + errcode + "，errmsg：" + jsonObject.get("errmsg"));
                            map = ResultMap.creatReault("12", "失败", "获取用户信息失败");
                            logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        if (errcode == null) { // 获取openid成功
                            // 解析返回参数
                            String openid = (String)openIdRes.get("openid");
                            if (!StringUtils.isNoneBlank(openid)) {
                                logger.error("获取的用户openid为空");
                                map = ResultMap.creatReault("13", "失败", "用户openid获取失败");
                                logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }

                            if (StringUtils.isNoneBlank(openid)) {
                                // 根据openid查询是否已注册（认证）
                                String checkWechartSql = "SELECT\n" +
                                                        "\tdw.dweller_id dwellerId \n" +
                                                        "FROM\n" +
                                                        "\tdweller d,\n" +
                                                        "\tdweller_wechat dw\n" +
                                                        "WHERE\n" +
                                                        "\td.ID = dw.dweller_id\n" +
                                                        "AND dw.openid = '" + openid + "'\n" +
                                                        "AND dw.version = " + version + "\n" +
                                                        "AND dw.visit_type = " + visitType + "\n" +
                                                        "AND dw.is_used = " + isUsed;

                                // 查询结果
                                List<Map<String, Object>> maps = baseDao.queryForList(checkWechartSql);
                                if (maps == null || maps.size() == 0) { // 需要弹出登录或者注册窗口，来讲微信信息绑定到居民身上
                                    logger.error("微信小程序 - 用户未注册（认证）");

                                    // TODO 微信小程序登录
                                    // 定义一个换取openid的code
                                    String key_code_openid = UUID.randomUUID().toString();
                                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                                    jedis.auth("q1w2e3r4t5");
                                    jedis.setex(key_code_openid, 7200, openid); // 2小时的有效期

                                    map = ResultMap.creatReault("5", "成功", "用户未注册（认证）");
                                    map.put("key_code_openid",key_code_openid);

                                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                                    jedis.close();
                                    return map;
                                }

                                if (maps != null && maps.size() > 0){ // 不用弹出登录或者注册窗口
                                    logger.error("微信小程序 - 用户已注册（认证）");

                                    // 需要将该居民信息绑定微信信息
                                    String dwellerWechartId = UUID.randomUUID().toString().replace("-", ""); // dweller_wechart表主键
                                    String dwellerId = (String) maps.get(0).get("dwellerId"); // 根据居民账号获取居民id

                                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                                    jedis.auth("q1w2e3r4t5");
                                    String wechartToken = jedis.get("wechartToken"); // 获取微信token

                                    String key_code_openid = UUID.randomUUID().toString();
                                    jedis.setex(key_code_openid, 7200, openid); // 2小时的有效期

                                    // 将此次登录录入居民微信表中
                                    String updateDwellerWechartSql = "INSERT INTO \n" +
                                                                        "\tdweller_wechat (\n" +
                                                                        "\t\tID,\n" +
                                                                        "\t\tdweller_id,\n" +
                                                                        "\t\topenid,\n" +
                                                                        "\t\twechat_token,\n" +
                                                                        "\t\tcreate_time,\n" +
                                                                        "\t\tstamp,\n" +
                                                                        "\t\tversion,\n" +
                                                                        "\t\tvisit_plat,\n" +
                                                                        "\t\tvisit_type,\n" +
                                                                        "\t\tis_used\n" +
                                                                        "\t)\n" +
                                                                    "VALUES\n" +
                                                                        "\t(\n" +
                                                                        "\t\t'" + dwellerWechartId + "',\n" +
                                                                        "\t\t'" + dwellerId + "',\n" +
                                                                        "\t\t'" + openid + "',\n" +
                                                                        "\t\t'" + wechartToken + "',\n" +
                                                                        "\t\t'" + createTime + "',\n" +
                                                                        "\t\t'" + stamp + "',\n" +
                                                                        "\t\t" + version + ",\n" +
                                                                        "\t\t" + visitPlat + ",\n" +
                                                                        "\t\t" + visitType + ",\n" +
                                                                        "\t\t" + isUsed + "\n" +
                                                                        "\t)\t";
                                    int update = baseDao.update(updateDwellerWechartSql);
                                    jedis.close();
                                    if (update <= 0) {
                                        logger.info("更新dweller_wechart表失败");
                                        map =  ResultMap.creatReault("77", "失败", "数据库操作失败");
                                        logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                                        return map;
                                    }
                                    map = ResultMap.creatReault("6", "成功", "用户已注册（认证）");
                                    map.put("key_code_openid",key_code_openid);
                                    map.put("dwellerId",dwellerId);
                                    logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
                                    return map;
                                }
                            }
                        }
                    }
                }
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (IOException e) {
            logger.info("向微信服务器发送请求失败异常：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("98", "失败", "参数类型错误");
            logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
            return map;
        }

        logger.info("出去《微信小程序 - 验证是否注册（认证）》wechartLogin()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 网页端和小程序 - 登录
     * @param param 包含账户密码或者key_code_openid(小程序用)
     * @return 结果集 - 是否需要注册（认证）
     */
    public LinkedHashMap<Object, Object> login(String param, HttpServletRequest request){
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer version = jsonObject.getInteger("version"); // 版本 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0:测试 1:生产
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否有效 0:有效 1:无效
                String dwellerIdcard = (String)jsonObject.get("dweller_idcard"); // 身份证号
                String dwellerPassword = (String)jsonObject.get("dweller_password"); // 密码

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (version == null) {
                    logger.info("参数version为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String createTime = DateUtil.format(new Date(stamp), "yyyy-MM-dd HH:mm:dd"); // 创建时间

                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerIdcard))) { // 账号为空
                    logger.info("账号dweller_idcard参数为空");
                    map =  ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerPassword))) { // 密码为空
                    logger.info("密码dweller_password参数为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // 根据访问平台的不同做不同的判断
                if (visitPlat == 0) { // 网页端
                    if (StringUtils.isNoneBlank(StringUtils.trim(dwellerIdcard)) && StringUtils.isNoneBlank(StringUtils.trim(dwellerPassword))) { // 账号密码不为空
                        // 查询账号密码是否存在
                        String checkAccountSql = "SELECT\n" +
                                                "\tdw.ID\n" +
                                                "FROM\n" +
                                                "\tdweller dw\n" +
                                                "WHERE\n" +
                                                "\tdw.dweller_idcard = '" + dwellerIdcard + "'\n" +
                                                "AND dw.password = '" + dwellerPassword + "'\n" +
                                                "AND dw.version = " + version + "\n" +
                                                "AND dw.visit_type = " + visitType + "\n" +
                                                "AND dw.is_used = " + isUsed;
                        List<Map<String, Object>> checkRes = baseDao.getAllByCondition(checkAccountSql);
                        if (checkRes == null || checkRes.size() == 0) { // 原因：1.未注册（认证）；2.账号或密码错误
                            logger.info("网页端 - 用户未注册（认证）");
                            map = ResultMap.creatReault("5", "成功", "用户未注册（认证）");
                            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        if (checkRes != null && checkRes.size() > 0) {
                            logger.info("网页端 - 用户已注册（认证）");

                            String dwId = (String) checkRes.get(0).get("ID"); // 用户id

                            // TODO 生成该用户对应的token，存入redis中
                            Jedis jedis = new Jedis("140.143.210.101", 6379);
                            jedis.auth("q1w2e3r4t5");

                            String systoken = UUID.randomUUID().toString().replace("-", ""); // 全局token

                            // 封装参数
                            Map<String, String> infoMap = new HashMap<String, String>();
                            infoMap.put("systoken", systoken);
                            infoMap.put("dwellerIdcard", dwellerIdcard);
                            infoMap.put("dwellerId", dwId);

                            jedis.hmset(systoken, infoMap);

                            Integer isApp = jsonObject.getInteger("isApp"); // 是否是app端 0是 1不是
                            if (isApp ==  null || isApp != 0) {
                                jedis.expire(systoken, 3600); // 设置有效期为1个小时
                            }

                            map = ResultMap.creatReault("6", "成功", "用户已注册（认证）");
                            map.put("dweller_id", dwId);
                            map.put("systoken", systoken);

                            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                            jedis.close();
                            return map;
                        }
                    }
                }

                if (visitPlat == 2) { // 小程序

                    String keyCodeOpenid = (String)jsonObject.get("key_code_openid"); // 换取openid用code

                    if (!StringUtils.isNoneBlank(StringUtils.trim(keyCodeOpenid))) { // keyCodeOpenid为空
                        logger.info("换取openid的keyCodeOpenid参数为空");
                        map = ResultMap.creatReault("88", "失败", "参数为空");
                        logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    if (StringUtils.isNoneBlank(StringUtils.trim(dwellerIdcard)) && StringUtils.isNoneBlank(StringUtils.trim(dwellerPassword))) { // 账号密码不为空
                        // 查询账号密码是否存在
                        String checkAccountSql = "SELECT\n" +
                                                    "\tdw.ID dwellerId\n" +
                                                "FROM\n" +
                                                    "\tdweller dw\n" +
                                                "WHERE\n" +
                                                    "\tdw.dweller_idcard = '" + dwellerIdcard + "'\n" +
                                                "AND dw.password = '" + dwellerPassword + "'\n" +
                                                "AND dw.version = " + version + "\n" +
                                                "AND dw.visit_type = " + visitType + "\n" +
                                                "AND dw.is_used = " + isUsed;
                        List<Map<String, Object>> checkRes = baseDao.getAllByCondition(checkAccountSql);
                        if (checkRes == null || checkRes.size() == 0) { // 居民没有注册（认证）过
                            logger.info("小程序 - 用户未注册（认证）");
                            map = ResultMap.creatReault("5", "成功", "用户未注册（认证）");
                            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        if (checkRes != null && checkRes.size() == 1) {
                            logger.info("小程序 - 用户已注册（认证）");

                            Jedis jedis = new Jedis("140.143.210.101", 6379);
                            jedis.auth("q1w2e3r4t5");
                            String wechartToken = jedis.get("wechartToken"); // 获取微信token
                            String openId = jedis.get(keyCodeOpenid); // 从redis中获取openid

                            // 需要将该居民信息绑定微信信息
                            String dwellerWechartId = UUID.randomUUID().toString().replace("-", ""); // dweller_wechart表主键
                            String dwellerId = (String) checkRes.get(0).get("dwellerId"); // 根据居民账号获取居民id

                            String updateDwellerWechartSql = "INSERT INTO \n" +
                                                                "\tdweller_wechat (\n" +
                                                                "\t\tID,\n" +
                                                                "\t\tdweller_id,\n" +
                                                                "\t\topenid,\n" +
                                                                "\t\twechat_token,\n" +
                                                                "\t\tcreate_time,\n" +
                                                                "\t\tstamp,\n" +
                                                                "\t\tversion,\n" +
                                                                "\t\tvisit_plat,\n" +
                                                                "\t\tvisit_type,\n" +
                                                                "\t\tis_used\n" +
                                                                "\t)\n" +
                                                            "VALUES\n" +
                                                                "\t(\n" +
                                                                "\t\t'" + dwellerWechartId + "',\n" +
                                                                "\t\t'" + dwellerId + "',\n" +
                                                                "\t\t'" + openId + "',\n" +
                                                                "\t\t'" + wechartToken + "',\n" +
                                                                "\t\t'" + createTime + "',\n" +
                                                                "\t\t'" + stamp + "',\n" +
                                                                "\t\t" + version + ",\n" +
                                                                "\t\t" + visitPlat + ",\n" +
                                                                "\t\t" + visitType + ",\n" +
                                                                "\t\t" + isUsed + "\n" +
                                                                "\t)\t";
                            int update = baseDao.update(updateDwellerWechartSql);
                            if (update <= 0) {
                                logger.info("更新dweller_wechart表失败");
                                map = ResultMap.creatReault("77", "失败", "数据库操作失败");
                                logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }

                            // 绑定微信成功
                            map = ResultMap.creatReault("6", "成功", "用户已注册（认证）");
                            map.put("dweller_id", dwellerId);
                            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }
                    }
                }
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("98", "失败", "参数类型错误");
            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
            return map;
        }

        logger.info("出去《微信小程序 - 登录》login()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 比对身份证和头像,并添加信息
     * @param param - 参数，头像，身份证图像，非业务参数等
     * @return 结果集 - 比对结果
     */
    public Object pageLogin(String param, HttpServletRequest request) {
        LinkedHashMap<Object, Object> map = null;
        Map<String, Object> paramMap = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 解析Json
                JSONObject jsonObj = JSON.parseObject(param);
                Long stamp = (Long)jsonObj.get("stamp"); // 时间戳
                Integer version = (Integer)jsonObj.get("version"); // 版本 0:测试 1:生产
                Integer visitPlat = (Integer)jsonObj.get("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer visitType = (Integer)jsonObj.get("visit_type"); // 访问类型 0:测试 1:生产
                Integer isUsed = (Integer)jsonObj.get("is_used"); // 是否有效 0:有效 1:无效

                String keyCodeOpenid = (String)jsonObj.get("key_code_openid"); // 换取openid

                String dwellerIdcard = (String) jsonObj.get("dweller_idcard"); // 居民账号 - 身份证号
                String dwellerPhone = (String) jsonObj.get("dweller_phone"); // 居民手机
                String dwellerPassword = (String) jsonObj.get("dweller_password"); // 居民密码

                // 参数非空判断
                if (visitPlat == 2) {
                    if (StringUtils.isBlank(StringUtils.trim(keyCodeOpenid))) {
                        logger.info("参数keyCodeOpenid为空");
                        map= ResultMap.creatReault("88", "失败", "参数为空");
                        logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }
                }
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (version == null) {
                    logger.info("参数version为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerIdcard))) { // 账号为空
                    logger.error("账号为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerPhone))) { // 密码为空
                    logger.error("密码为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerPassword))) { // 手机号为空
                    logger.error("手机号为空");
                    map= ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String createTime = DateUtil.format(new Date(stamp), "yyyy-MM-dd HH:mm:dd"); // 创建时间

                // 根据上传的两张图片进行比对
                String idcardImgBase64 = (String)jsonObj.get("idcardImg"); // 身份证图片路径
//                idcardImgBase64 = FileUtils.encryptToBase64("C:\\upload\\idcardZ.jpg"); // test
                if (!StringUtils.isNoneBlank(idcardImgBase64)) {
                    logger.error("身份证图片路径为空");
                    map = ResultMap.creatReault("881", "失败", "身份证图片信息为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String headImgBase64 = (String)jsonObj.get("headImg"); // 本人头像路径
//                headImgBase64 = FileUtils.encryptToBase64("C:\\upload\\headImg.jpg"); // test
                if (!StringUtils.isNoneBlank(headImgBase64)) {
                    logger.error("头像图片路径为空");
                    map = ResultMap.creatReault("882", "失败", "头像图片信息为空");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // ***** 防止多次提交 *****
                Map<String, Object> regist = (Map<String, Object>)regist(param, request);
                if (StringUtils.equals((String)regist.get("status"), "12")) { // 已注册
                    logger.error("不能重复注册");
                    map = ResultMap.creatReault("1", "失败", "重复注册");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // 后台经图片转成base64 2018-07-08
                if (visitPlat == 2) { // 小程序通过后台来讲图片转成base64
                    idcardImgBase64 = HttpToQiNiu.getBase64(idcardImgBase64);
                    headImgBase64 = HttpToQiNiu.getBase64(headImgBase64);
                }

                // 1.调用第三方接口解析身份证图像，获取身份证相关信息，包括姓名，身份证号，头像等信息
                // a.封装参数
                paramMap = new HashMap<String, Object>();
                paramMap.put("key", ApiConstants.ACCESS_KEY); // 平台账户秘钥秘钥
                paramMap.put("bas64String", idcardImgBase64); // 身份证图像base64码
                paramMap.put("side", 1); // 身份证正反面  1正面 2反面

                // b.向平台发送请求
                String idcardInfoResJson = APIStoreGetIDcardInfo.doPost(ApiConstants.IDCARD_GET_INFO_URL, APIStoreGetIDcardInfo.urlencode(paramMap));
                if (idcardInfoResJson == null) { // 获取身份证信息失败
                    logger.error("发送提取身份证信息返回参数为空");
                    map = ResultMap.creatReault("771", "失败", "提取身份证信息失败");
                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // c.解析返回结果
                JSONObject idcardInfoResJsonObject = JSON.parseObject(idcardInfoResJson);
                if (idcardInfoResJsonObject != null) { // 发送请求成功
                    // d.获取错误码
                    Integer errorCode = (Integer)idcardInfoResJsonObject.get("error_code");
                    if (errorCode != 0) { // 可能是照片顺序的问题，调换一下图片顺序，继续验证
                        headImgBase64 = (String)jsonObj.get("idcardImg"); // 身份证图片路径
                        idcardImgBase64  = (String)jsonObj.get("headImg"); // 本人头像路径

                        // 替换封装参数中的身份证图片路径
                        paramMap.put("bas64String", idcardImgBase64); // 身份证图像base64码

                        // bb.向平台发送请求
                        idcardInfoResJson = APIStoreGetIDcardInfo.doPost(ApiConstants.IDCARD_GET_INFO_URL, APIStoreGetIDcardInfo.urlencode(paramMap));
                        if (idcardInfoResJson == null) { // 获取身份证信息失败
                            logger.error("发送提取身份证信息返回参数为空");
                            map = ResultMap.creatReault("771", "失败", "提取身份证信息失败");
                            logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        // cc.解析返回结果
                        idcardInfoResJsonObject = JSON.parseObject(idcardInfoResJson);
                        if (idcardInfoResJsonObject != null) {
                            // 获取状态码
                            errorCode = (Integer)idcardInfoResJsonObject.get("error_code");
                            if (errorCode != 0) {
                                logger.error("错误状态码：" + (Integer)idcardInfoResJsonObject.get("error_code") + "，错误提示：" + (String)idcardInfoResJsonObject.get("reason"));
                                map = ResultMap.creatReault("771", "失败", "提取身份证信息失败");
                                logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }
                        }
                    }

                    Integer checkFlag = 0; // 未认证

                    if (errorCode == 0) { // 获取信息成功
                        // 获取身份证正反面标识
                        JSONObject result = (JSONObject) idcardInfoResJsonObject.get("result");
                        Integer side = (Integer)result.get("side");
                        if (side == 2) {
                            logger.error("上传了身份证反面图片");
                            map = ResultMap.creatReault("772", "失败", "上传身份证正面照");
                            logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        // 姓名
                        String name = (String)result.get("name");
                        // 身份证号码
                        String num = (String)result.get("num");

                        // 判断输入的身份证号和上传的身份证图像信息是否一致
                        if (!StringUtils.equals(num, dwellerIdcard)) {
                            logger.info("账号和身份证图像信息不符");
                            map = ResultMap.creatReault("774", "失败", "账号和身份证图像信息不符");
                            logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                            return map;
                        }

                        if (StringUtils.isNoneBlank(name) && StringUtils.isNoneBlank(num)) {
                            // 2.调用第三方接口比对身份证和上传的头像是否是同一个人
                            // a.封装参数
                            paramMap = new HashMap<String, Object>();
                            paramMap.put("key", ApiConstants.ACCESS_KEY); // 平台账户秘钥秘钥
                            paramMap.put("realName", name); // 真实姓名
                            paramMap.put("cardNo", num); // 身份证号
                            paramMap.put("img",headImgBase64); // 图片base64码或者是图片地址（可以下载的）

                            // b.向第三方发送请求，返回比对结果
                            String compareResJsonStr = APIStoreCompareIdcardPhoto.doPost(ApiConstants.IDCARD_COMPARE_PHOTO_URL, APIStoreCompareIdcardPhoto.urlencode(paramMap));
                            if (!StringUtils.isNoneBlank(compareResJsonStr)) {
                                logger.error("身份证和头像比对失败");
                                map = ResultMap.creatReault("773", "失败", "身份证和头像比对失败");
                                logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }

                            // c.解析返回结果
                            JSONObject idcardCompareResJsonObject = JSON.parseObject(compareResJsonStr);
                            if (idcardCompareResJsonObject != null) {
                                // 获取错误码
                                Integer errorCode2 = (Integer)idcardCompareResJsonObject.get("error_code");

                                if (errorCode2 != 0) { // 头像身份证比对失败
                                    logger.info("头像与身份证信息不符");
                                    map = ResultMap.creatReault("775", "失败", "身份证和头像信息不符");
                                    logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                    return map;
                                }

                                if (errorCode2 == 0){ // 头像身份证比对成功

                                    checkFlag = 1; // 认证成功

                                    // 将居民的信息存入数据库
                                    // 动态参数
                                    List<Object> tags = new ArrayList<Object>();

                                    // 生成居民记录主键
                                    String dwellerId = UUID.randomUUID().toString().replace("-", ""); // 主键

                                    // 封装sql
                                    StringBuilder sql = new StringBuilder();
                                    StringBuilder sqlParm = new StringBuilder();
                                    StringBuilder sqlData = new StringBuilder();

                                    if (stamp != null){
                                        sqlParm.append("stamp").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(stamp);
                                    }
                                    if (StringUtils.isNoneBlank(createTime)) {
                                        sqlParm.append("create_time").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(createTime);
                                    }
                                    if (version != null) {
                                        sqlParm.append("version").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(version);
                                    }
                                    if (visitPlat != null) {
                                        sqlParm.append("visit_plat").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(visitPlat);
                                    }
                                    if (visitType != null) {
                                        sqlParm.append("visit_type").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(visitType);
                                    }
                                    if (isUsed != null) {
                                        sqlParm.append("is_used").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(isUsed);
                                    }
                                    if (StringUtils.isNoneBlank(name)) {
                                        sqlParm.append("dweller_name").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(name);
                                    }
                                    if (StringUtils.isNoneBlank(num)) {
                                        sqlParm.append("dweller_idcard").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(num);
                                    }
                                    if (StringUtils.isNoneBlank(dwellerPhone)) {
                                        sqlParm.append("telphone").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(dwellerPhone);
                                    }
                                    if (StringUtils.isNoneBlank(dwellerPassword)) {
                                        sqlParm.append("password").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(dwellerPassword);
                                    }
                                    if (checkFlag != null) {
                                        sqlParm.append("check_flag").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(checkFlag);
                                    }
                                    if (StringUtils.isNoneBlank(dwellerId)) {
                                        sqlParm.append("ID").append(",");
                                        sqlData.append("?").append(",");
                                        tags.add(dwellerId);
                                    }

                                    if (sqlParm.toString().endsWith(",")) {
                                        sqlParm = sqlParm.deleteCharAt(sqlParm.toString().length() - 1);
                                    }
                                    if (sqlData.toString().endsWith(",")) {
                                        sqlData = sqlData.deleteCharAt(sqlData.toString().length() - 1);
                                    }

                                    sql.append("insert into dweller("+sqlParm+") values("+sqlData+")");
                                    logger.info("插入dweller表 sql：" + sql.toString());
                                    int update = baseDao.update(sql.toString(), tags.toArray());
                                    if (update <= 0) {
                                        logger.info("插入dweller表数据失败");
                                        map = ResultMap.creatReault("77", "失败", "数据库操作失败");
                                        logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                        return map;
                                    }

                                    map = ResultMap.creatReault("0", "成功", "注册（认证）成功");
                                    map.put("dweller_id", dwellerId);

                                    // 清空
                                    tags.clear();

                                    if (visitPlat == 2) { // 小程序进来的，才会将居民的微信openid存入数据库
                                        Jedis jedis = new Jedis("140.143.210.101", 6379);
                                        jedis.auth("q1w2e3r4t5");

//                                        // 解析json字符串
//                                        JSONObject jsonObject = JSON.parseObject(baseInfo);
//                                        String openId = (String) jsonObject.get("openId"); // 微信小程序 - openid
//                                        String sessionKey = (String) jsonObject.get("sessionKey"); // 微信小程序 - sessionKey
//                                        String unionId = (String) jsonObject.get("unionId"); // 微信小程序 - unionId
                                        String wechartToken = jedis.get("wechartToken"); // 微信小程序 - token

                                        String openId = jedis.get(keyCodeOpenid); // 换取openid

//                                        String openId = (String)request.getSession().getAttribute(keyCodeOpenid); // 换取openid

                                        // 获取session中相关微信信息
                                        if (openId != null && wechartToken != null) {
                                            // 封装sql
                                            sql = new StringBuilder();
                                            sqlParm = new StringBuilder();
                                            sqlData = new StringBuilder();

                                            // 生成居民微信记录主键
                                            String dwellerWechartId = UUID.randomUUID().toString().replace("-", ""); // 主键

                                            if (StringUtils.isNoneBlank(dwellerWechartId)) {
                                                sqlParm.append("ID").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(dwellerWechartId);
                                            }
                                            if (StringUtils.isNoneBlank(openId)) {
                                                sqlParm.append("openid").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(openId);
                                            }
                                            if (StringUtils.isNoneBlank(dwellerId)) {
                                                sqlParm.append("dweller_id").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(dwellerId);
                                            }
                                            if (StringUtils.isNoneBlank(wechartToken)) {
                                                sqlParm.append("wechat_token").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(wechartToken);
                                            }
                                            if (stamp != null){
                                                sqlParm.append("stamp").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(stamp);
                                            }
                                            if (StringUtils.isNoneBlank(createTime)) {
                                                sqlParm.append("create_time").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(createTime);
                                            }
                                            if (version != null) {
                                                sqlParm.append("version").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(version);
                                            }
                                            if (visitPlat != null) {
                                                sqlParm.append("visit_plat").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(visitPlat);
                                            }
                                            if (visitType != null) {
                                                sqlParm.append("visit_type").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(visitType);
                                            }
                                            if (isUsed != null) {
                                                sqlParm.append("is_used").append(",");
                                                sqlData.append("?").append(",");
                                                tags.add(isUsed);
                                            }

                                            if (sqlParm.toString().endsWith(",")) {
                                                sqlParm = sqlParm.deleteCharAt(sqlParm.toString().length() - 1);
                                            }
                                            if (sqlData.toString().endsWith(",")) {
                                                sqlData = sqlData.deleteCharAt(sqlData.toString().length() - 1);
                                            }

                                            sql.append("insert into dweller_wechat("+sqlParm+") values("+sqlData+")");
                                            logger.info("插入dweller_wechat表 sql：" + sql.toString());

                                            // 更新表数据
                                            int update2 = baseDao.update(sql.toString(), tags.toArray());
                                            if (update2 <= 0) {
                                                logger.info("插入dweller_wechat表数据失败");
                                                map = ResultMap.creatReault("77", "失败", "数据库操作失败");
                                                logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                                return map;
                                            }

                                            map = ResultMap.creatReault("0", "成功", "注册（认证）成功");
                                            map.put("dweller_id", dwellerId);
                                        }
                                        jedis.close();
                                    }
                                }
                            } else { // 头像信息比对失败
                                logger.error("错误状态码：" + (Integer)idcardInfoResJsonObject.get("error_code") + "，错误提示：" + (String)idcardInfoResJsonObject.get("reason"));
                                map = ResultMap.creatReault("771", "失败", "提取身份证信息失败");
                                logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }
                        }
                    }
                }
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("98", "失败", "参数类型错误");
            logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            return map;
        }

        logger.info("出去《微信小程序 - 注册（认证）》pageLogin()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 异步验证账号是否已注册
     * @param param 包含账号信息
     * @return 结果集 账号是否注册
     */
    public Object regist(String param, HttpServletRequest request) {

        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer version = jsonObject.getInteger("version"); // 版本 0:测试 1:生产
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否有效 0:有效 1:无效

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (version == null) {
                    logger.info("参数version为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String createTime = DateUtil.format(new Date(stamp), "yyyy-MM-dd HH:mm:dd"); // 更新时间yyyy-MM-dd HH:mm:ss

                String dwellerIdcard = (String)jsonObject.get("dweller_idcard"); // 居民账号 - 身份证号
                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerIdcard))) { // 是否为空
                    logger.error("居民账号dweller_idcard参数为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // 根据账号查询是否存在
                String sql = "SELECT\n" +
                            "\tdw.ID\n" +
                            "FROM\n" +
                            "\tdweller dw\n" +
                            "WHERE\n" +
                            "\tdw.dweller_idcard = '" + dwellerIdcard + "'\n" +
                            "AND dw.version = "+version+"\n" +
                            "AND dw.visit_type = "+visitType+"\n" +
                            "AND dw.is_used = "+isUsed;
                List<Map<String, Object>> mapList = baseDao.getAllByCondition(sql);

                if (mapList == null || mapList.size() == 0) {
                    logger.info("账号不存在");
                    map = ResultMap.creatReault("11", "成功", "账号不存在");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                if (mapList != null && mapList.size() == 1) {
                    logger.info("账号已存在");
                    map = ResultMap.creatReault("12", "成功", "账号已存在");
                    logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("98", "失败", "参数类型错误");
            logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            return map;
        }

        logger.info("出去《微信小程序 - 异步验证账号是否已注册》regist()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 业务预约
     * @param param 预约信息
     * @param request 请求
     * @return 结果集 - 预约结果
     */
    public Object appointment(String param, HttpServletRequest request) {
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 解析相关参数
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否失效 0:有效 1:无效
                Integer version = jsonObject.getInteger("version"); // 数据版本 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0网页 1一体机 2小程序 3其他
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0测试 1生产

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (version == null) {
                    logger.info("参数version为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String createTime = DateUtil.format(new Date(stamp), "yyyy-MM-dd HH:mm:dd"); // 更新时间yyyy-MM-dd HH:mm:ss

                String systoken = null;
                if (visitPlat == 0) { // 网页端
                        systoken = (String)jsonObject.get("systoken"); // 全局token
                    if (StringUtils.isBlank(systoken)) {
                        logger.info("systoken为空");
                        map = ResultMap.creatReault("33", "失败", "token为空");
                        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }
                }

                // 预约参数
                String appointmentTime = (String)jsonObject.get("time"); // 预约时间
                String depId = (String)jsonObject.get("dep_id"); // 部门ID
                String bizzId = (String)jsonObject.get("bizz_id"); // 业务ID
                Integer isSocityBizz = jsonObject.getInteger("is_socity_bizz"); // 业务员类型 0 社区直通 1 第三方接口 2其他
                Integer bizzType = jsonObject.getInteger("bizz_type"); // 业务办理状态 1 预约2 本社区待审核 3 本社区通过（4失败）5第三方已提交 6第三方待审核 7第三方成功（8第三方失败） 9 其他

                String dwellerId = (String)jsonObject.get("dweller_id"); // 居民Id
                if (!StringUtils.isNoneBlank(StringUtils.trim(dwellerId))) {
                    logger.info("参数dweller_id为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (!StringUtils.isNoneBlank(StringUtils.trim(depId))) {
                    logger.info("参数dep_id为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (!StringUtils.isNoneBlank(StringUtils.trim(bizzId))) {
                    logger.info("参数bizz_id为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (isSocityBizz == null) {
                    logger.info("参数is_socity_bizz为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
                if (bizzType == null) {
                    logger.info("参数bizz_type为空");
                    map = ResultMap.creatReault("88", "失败", "参数为空");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // 根据访问平台的不同从session中获取不同的值
                String dwellerIdcard = null;
                if (visitPlat == 0) { // 网页端

                    // 根据身份证从redis中获取token
                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                    jedis.auth("q1w2e3r4t5");

                    List<String> infoList = jedis.hmget(systoken, "systoken",  "dwellerIdcard", "dwellerId");
                    String systokenRedis = null;
                    if (infoList != null && infoList.size() > 0) {
                        systokenRedis = infoList.get(0); // token
                        dwellerIdcard = infoList.get(1); // 居民身份证号
                        dwellerId = infoList.get(2); // 居民唯一标识
                    }

                    // 查看token是否过期
                    if (StringUtils.isBlank(systokenRedis)) { // 重新登录，弹出登录框
                        logger.info("全局systoken过期，需要重新获取systoken");
                        map = ResultMap.creatReault("33", "失败", "systoken过期");
                        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    // token不一致
                    if (!StringUtils.equals(systokenRedis, systoken)) {
                        logger.info("用户访问的token不一致");
                        map = ResultMap.creatReault("331", "失败", "systoken不一致");
                        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                }

                if (visitPlat == 2) { // 小程序
                    String keyCodeOpenid = (String)jsonObject.get("key_code_openid"); // 换取openid
                    if (StringUtils.isBlank(StringUtils.trim(keyCodeOpenid))) {
                        logger.info("参数visit_type为空");
                        map = ResultMap.creatReault("88", "失败", "参数为空");
                        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                    jedis.auth("q1w2e3r4t5");
                    String openId = jedis.get(keyCodeOpenid);

                    // 根据openid查询出居民Id
                    String queryDwellerId = "SELECT\n" +
                                                "\td.ID dwellerId,\n" +
                                                "\td.dweller_idcard dwellerIdcard\n" +
                                            "FROM\n" +
                                                "\tdweller d,\n" +
                                                "\tdweller_wechat dw\n" +
                                            "WHERE\n" +
                                                "\td.ID = dw.dweller_id\n" +
                                            "AND dw.openid = '" + openId + "'\n"+
                                            "AND d.version = " + version + "\n" +
                                            "AND d.visit_type = " + visitType + "\n" +
                                            "AND d.is_used = " + isUsed + "\n" +
                                            "AND dw.version = " + version + "\n" +
                                            "AND dw.visit_type = " + visitType + "\n" +
                                            "AND dw.is_used = " + isUsed + "\n" +
                                            "GROUP BY dw.dweller_id";
                    List<Map<String, Object>> dwellerIdList = baseDao.getAllByCondition(queryDwellerId);
                    if (dwellerIdList == null || dwellerIdList.size() <= 0) {
                        logger.info("微信没有关联居民信息");
                        map = ResultMap.creatReault("332", "失败", "微信没有关联居民信息");
                        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                        return map;
                    }

                    dwellerId = (String) dwellerIdList.get(0).get("dwellerId"); // 居民id
                }

                // 1.查询该用户提交的预约日期在数据库中是否存在
                String isBespeakSql = "SELECT\n" +
                                    "\tCOUNT(bs.ID) as count\n" +
                                    "FROM\n" +
                                    "\tbespeak bs\n" +
                                    "WHERE\n" +
                                    "\tbs.time = '"+appointmentTime+"'\n" +
                                    "AND bs.dep_id = '"+depId+"'\n" +
                                    "AND bs.bizz_id = '"+bizzId+"'\n" +
                                    "AND bs.is_socity_bizz = "+isSocityBizz+"\n" +
                                    "AND bs.bizz_type = "+bizzType+"\n" +
                                    "AND bs.dweller_id = '"+dwellerId+"'\n" +
                                    "AND bs.version = "+version+"\n" +
                                    "AND bs.visit_type = "+visitType+"\n" +
                                    "AND bs.is_used = "+isUsed+"";
                Long isBespeakCount = baseDao.getCount(isBespeakSql);
                if (isBespeakCount >= 1) {
                    logger.info("该用户已预约 " + appointmentTime + " 的业务");
                    map = ResultMap.creatReault("333", "失败", "重复预约");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                String bespeakId = UUID.randomUUID().toString().replace("-", ""); // 预约记录主键
                String officerId = null; // 办公人员Id
                /**
                 * 将该预约进行任务派发
                 */
                // 1.查询该部门下有多少个员工
                String queryDepOfficer = "SELECT\n" +
                                            "\tdistinct od.officer_id officerId\n" +
                                         "FROM\n" +
                                            "\tofficer_department od\n" +
                                         "WHERE\n" +
                                            "\tod.dep_id = '" + depId + "'\n" +
                                         "AND od.parent_id IS NOT NULL\n" +
                                         "AND od.version = " + version + "\n" +
                                         "AND od.visit_type = " + visitType + "\n" +
                                         "AND od.is_used = " + isUsed + "";
                List<Map<String, Object>> allOfficerDep = baseDao.getAllByCondition(queryDepOfficer);
                // a.只有一个员工
                if (allOfficerDep != null && allOfficerDep.size() == 1) {
                    officerId = (String) allOfficerDep.get(0).get("officerId");
                }

                List<String> officerIdList = new ArrayList<String>(); // 该部门下的全部员工id
                // b.有多个员工
                if (allOfficerDep != null && allOfficerDep.size() > 1) {
                    // 遍历集中工作人员id
                    for (Map<String, Object> officerMap: allOfficerDep) {
                        String officerIdAll = (String) officerMap.get("officerId");
                        officerIdList.add(officerIdAll); // 集中工作人员id
                    }

                    // b1.查询该部门下的办事人员不接受预约的情况
                    String queryCancelSql = "SELECT\n" +
                                                "\tcb.officer_id officerId,\n" +
                                                "\tcb.cancel_type cancelType,\n" +
                                                "\tcbt.per_long perLong,\n" +
                                                "\tcbt.start_time startTime,\n" +
                                                "\tcbt.end_time endTime,\n" +
                                                "\tcbt.at_date_day atDateDay,\n" +
                                                "\tcbt.at_date_week atDateWeek,\n" +
                                                "\tcbt.at_date_month atDateMonth\n" +
                                            "FROM\n" +
                                                "\tcancel_bespeak cb,\n" +
                                                "\tcancel_bespeak_time cbt,\n" +
                                                "\tofficer_department od\n" +
                                            "WHERE\n" +
                                                "\tcb.ID = cbt.cancel_bes_id\n" +
                                            "AND cb.officer_id = od.officer_id\n" +
                                            "AND od.dep_id = '" + depId + "'\n" +
                                            "AND od.parent_id IS NOT NULL\n" +
                                            "AND od.visit_type = " + visitType + " \n" +
                                            "AND od.version = " + version + " \n" +
                                            "AND od.is_used = " + isUsed + " \n" +
                                            "AND cb.visit_type = " + visitType + " \n" +
                                            "AND cb.version = " + version + " \n" +
                                            "AND cb.is_used = " + isUsed + " \n" +
                                            "AND cbt.visit_type = " + visitType + " \n" +
                                            "AND cbt.version = " + version + " \n" +
                                            "AND cbt.is_used = " + isUsed;
                    List<Map<String, Object>> officerList = baseDao.getAllByCondition(queryCancelSql);
                    // b2.查询结果为空，说明每个员工都正常接受预约
                    if (officerList == null || officerList.size() == 0) {
                        // b21.根据任务承担量的多少进行分发
                        String countOfficerBizz = "SELECT\n" +
                                                      "\tcount(1) count,\n" +
                                                      "\tddb.officer_id officerId\n" +
                                                  "FROM\n" +
                                                      "\tofficer_department od,\n" +
                                                      "\tbespeak ddb\n" +
                                                  "WHERE\n" +
                                                    "\tod.officer_id = ddb.officer_id\n" +
                                                  "AND od.dep_id = '" + depId + "'\n" +
                                                  "AND od.parent_id IS NOT NULL\n" +
                                                  "AND od.version = " + version + " \n" +
                                                  "AND od.visit_type = " + visitType + " \n" +
                                                  "AND od.is_used = " + isUsed + " \n" +
                                                  "AND ddb.version = " + version + " \n" +
                                                  "AND ddb.visit_type = " + visitType + " \n" +
                                                  "AND ddb.is_used = " + isUsed + " \n" +
                                                  "GROUP BY ddb.officer_id\n" +
                                                  "ORDER BY count, ddb.officer_id ASC\n";
                        List<Map<String, Object>> coutList = baseDao.getAllByCondition(countOfficerBizz);
                        if (coutList == null || coutList.size() ==0) { // 每个员工都没有任务
                            officerId = (String) allOfficerDep.get(0).get("officerId");
                        }

                        if (coutList != null && coutList.size() == allOfficerDep.size()) { // 每个员工都有任务
                            officerId = (String) coutList.get(0).get("officerId");
                        }

                        if (coutList != null && coutList.size() < allOfficerDep.size() && coutList.size() != 0) { // 有员工没有任务
                            List<String> officerIdBizzList = new ArrayList<String>(); // 有任务办事人员id集合
                            for (Map<String, Object> officerMap: coutList) {
                                String officerIdAll = (String) officerMap.get("officerId");
                                officerIdBizzList.add(officerIdAll); // 集中工作人员id
                            }

                            // 去除全部员工Id集合中的有任务的员工id
                            officerIdList.remove(officerIdBizzList);
                            // 判断剩余员工id集合数量
                            if (officerIdList.size() == 1) { // 只有一个
                                officerId = officerIdList.get(0);
                            }

                            if (officerIdList.size() > 1) { // 有多个
                                officerId = officerIdList.get(1);
                            }
                        }
                    }

                    // b3.查询结果不为空，说明有员工出现了不接受预约的情况
                    if (officerList != null && officerList.size() > 0) {
                            List<String> officerIdCancelList = new ArrayList<String>(); // 有不接受预约情况的办事人员id集合
                        for (Map<String, Object> officerMap: officerList) {
                            String officerIdAll = (String) officerMap.get("officerId");
                            officerIdCancelList.add(officerIdAll); // 集中不接受预约情况工作人员id，可能会重复
                        }

                        // 去重
                        officerIdCancelList = new ArrayList<>(new TreeSet<>(officerIdCancelList));

                        if (officerIdCancelList.size() == allOfficerDep.size()) { // 每个员工都有不接受预约的情况

                            List<String> acceptIdList = new ArrayList<String>(); // 可以接收预约的员工id
                            long startTimeMill = 0L;
                            long endTimeMill = 0L;
                            for (int i = 0; i < officerList.size(); i++) {

                                // 获取不接受预约的初始时间startTime
                                String startTimeStr = (String) officerList.get(i).get("startTime");
                                if (StringUtils.isNoneBlank(StringUtils.trim(startTimeStr))) {
                                    Date parse = DateUtil.parse(startTimeStr, "yyyy-MM-dd");
                                    startTimeMill = parse.getTime();
                                }
                                // 获取不接受预约的结束时间endTime
                                String endTimeStr = (String) officerList.get(i).get("endTime");
                                if (StringUtils.isNoneBlank(StringUtils.trim(endTimeStr))) {
                                    Date parse = DateUtil.parse(endTimeStr, "yyyy-MM-dd");
                                    endTimeMill = parse.getTime();
                                }

                                // 预约的时间的毫秒值
                                Date parse = DateUtil.parse(appointmentTime, "yyyy-MM-dd");
                                long appointTimeMill = parse.getTime();

                                if (appointTimeMill < startTimeMill || appointTimeMill > endTimeMill) { // 这个员工有时间
                                    acceptIdList.add((String)officerList.get(i).get("officerId"));
                                }

//                                Integer perLong = (Integer) allOfficerDep.get(i).get("perLong"); // 不接受预约类型 0：1天 1:一周  2:一月
//                                switch (perLong){
//                                    case 0: // 一天
//                                        String day = (String)allOfficerDep.get(i).get("atDateDay");
//                                        day = DateUtil.format(DateUtil.parse(day, "yyyy-MM-dd"), "yyyy-MM-dd");
//                                        appointmentTime = DateUtil.format(DateUtil.parse(appointmentTime, "yyyy-MM-dd"), "yyyy-MM-dd");
//                                        if (!StringUtils.equals(day, appointmentTime)) {
//                                            acceptIdList.add((String)allOfficerDep.get(i).get("officerId"));
//                                        }
//                                        break;
//                                    case 1: // 一周
//                                        String week = (String)allOfficerDep.get(i).get("atDateWeek");
//                                        Calendar c = Calendar.getInstance();
//                                        c.setTime(DateUtil.parse(appointmentTime, "yyyy-MM-dd"));
//                                        String dayOfWeek = null;
//                                        if (c.get(Calendar.DAY_OF_WEEK) == 1) {
//                                            dayOfWeek = "周日";
//                                        } else {
//                                            int dayOfWeekInt = c.get(Calendar.DAY_OF_WEEK) - 1;
//                                            switch (dayOfWeekInt) {
//                                                case 1:
//                                                    dayOfWeek = "周一";
//                                                    break;
//                                                case 2:
//                                                    dayOfWeek = "周二";
//                                                    break;
//                                                case 3:
//                                                    dayOfWeek = "周三";
//                                                    break;
//                                                case 4:
//                                                    dayOfWeek = "周四";
//                                                    break;
//                                                case 5:
//                                                    dayOfWeek = "周五";
//                                                    break;
//                                                case 6:
//                                                    dayOfWeek = "周六";
//                                                    break;
//                                                default:
//                                                    break;
//                                            }
//                                        }
//
//                                        if (!StringUtils.equals(week, dayOfWeek)) {
//                                            acceptIdList.add((String)allOfficerDep.get(i).get("officerId"));
//                                        }
//                                        break;
//                                    case 2: // 一个月
//                                        String month = (String)allOfficerDep.get(i).get("atDateMonth");
//                                        appointmentTime = DateUtil.format(DateUtil.parse(appointmentTime, "yyyy-MM-dd"), "yyyy-MM-dd");
//                                        String sub = appointmentTime.substring(appointmentTime.length() - 2, appointmentTime.length());
//                                        if (!StringUtils.equals(month, month)) {
//                                            acceptIdList.add((String)allOfficerDep.get(i).get("officerId"));
//                                        }
//                                        break;
//                                    default:
//                                        break;
//                                }
                            }

                            if (acceptIdList == null || acceptIdList.size() ==0) { // 预约时间冲突
                                logger.info("预约时间冲突");
                                map = ResultMap.creatReault("22", "失败", "预约日期冲突");
                                logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                                return map;
                            }

                            if (acceptIdList != null) {
                                if (acceptIdList.size() == 1) { // 只有一名员工可以接受预约
                                    officerId = acceptIdList.get(0);
                                }

                                if (acceptIdList.size() > 1) { // 有多名员工可以接受预约

                                    StringBuilder officerIdStrB = new StringBuilder();
                                    for (String offId: acceptIdList) {
                                        officerIdStrB.append("\"").append(offId).append("\"").append(",");
                                    }

                                    String officerIdStr = officerIdStrB.substring(0,officerIdStrB.toString().length() - 1 );

                                    List<String> bizzOfficerList = new ArrayList<String>(); // 存在接收预约办事人员id，业务集合
                                    // b21.根据任务承担量的多少进行分发
                                    String countOfficerBizz = "SELECT\n" +
                                                                  "\tcount(1) count,\n" +
                                                                  "\tddb.officer_id officerId\n" +
                                                              "FROM\n" +
                                                                  "\tofficer_department od,\n" +
                                                                  "\tbespeak ddb\n" +
                                                              "WHERE\n" +
                                                                   "\tod.officer_id = ddb.officer_id\n" +
                                                              "AND ddb.officer_id in(" + officerIdStr + ")\n" +
                                                              "AND od.parent_id IS NOT NULL\n" +
                                                              "AND od.version = " + version + " \n" +
                                                              "AND od.visit_type = " + visitType + " \n" +
                                                              "AND od.is_used = " + isUsed + " \n" +
                                                              "AND ddb.version = " + version + " \n" +
                                                              "AND ddb.visit_type = " + visitType + " \n" +
                                                              "AND ddb.is_used = " + isUsed + " \n" +
                                                              "GROUP BY ddb.officer_id\n" +
                                                              "ORDER BY count, ddb.officer_id ASC\n";
                                    List<Map<String, Object>> coutList = baseDao.getAllByCondition(countOfficerBizz);

                                    if (coutList == null || coutList.size() ==0) { // 每个员工都没有任务
                                        officerId = (String) allOfficerDep.get(0).get("officerId");
                                    }

                                    if (coutList != null && coutList.size() == allOfficerDep.size()) { // 每个员工都有任务
                                        officerId = (String) coutList.get(0).get("officerId");
                                    }

                                    if (coutList != null && coutList.size() < allOfficerDep.size() && coutList.size() != 0) { // 有员工没有任务
                                        List<String> officerIdBizzList = new ArrayList<String>(); // 有任务办事人员id集合
                                        for (Map<String, Object> officerMap: coutList) {
                                            String officerIdAll = (String) officerMap.get("officerId");
                                            officerIdBizzList.add(officerIdAll); // 集中工作人员id
                                        }

                                        // 去除全部员工Id集合中的有任务的员工id
                                        officerIdList.remove(officerIdBizzList);
                                        // 判断剩余员工id集合数量
                                        if (officerIdList.size() == 1) { // 只有一个
                                            officerId = officerIdList.get(0);
                                        }

                                        if (officerIdList.size() > 1) { // 有多个
                                            officerId = officerIdList.get(1);
                                        }
                                    }
                                }
                            }
                        }

                        if (officerIdList.size() - officerIdCancelList.size() == 1) { // 有一个办事人员全部时间都接收
                            List<String> officerIdList1 = new ArrayList<>(officerIdList); // 副本
                            officerIdList1.removeAll(officerIdCancelList); // 移除不接受预约情况的办事人员id
                            officerId = officerIdList1.get(0);
                        }

                        if (allOfficerDep.size() - officerIdCancelList.size() > 1) { // 有多个办事人员全部时间都接收
                            List<String> officerIdList1 = new ArrayList<>(officerIdList); // 副本
                            officerIdList1.removeAll(officerIdCancelList); // 移除不接受预约情况的办事人员id
                            officerIdList = officerIdList1;

                            StringBuilder officerIdStrB = new StringBuilder();
                            for (String offId: officerIdList) {
                                officerIdStrB.append("\"").append(offId).append("\"").append(",");
                            }

                            String officerIdStr = officerIdStrB.substring(0,officerIdStrB.toString().length() - 1 );

                            List<String> bizzOfficerList = new ArrayList<String>(); // 存在接收预约办事人员id，业务集合
                            // b21.根据任务承担量的多少进行分发
                            String countOfficerBizz = "SELECT\n" +
                                                         "\tcount(1) count,\n" +
                                                         "\tddb.officer_id officerId\n" +
                                                      "FROM\n" +
                                                         "\tofficer_department od,\n" +
                                                         "\tbespeak ddb\n" +
                                                      "WHERE\n" +
                                                        "\tod.officer_id = ddb.officer_id\n" +
                                                      "AND ddb.officer_id in(" + officerIdStr + ")\n" +
                                                      "AND od.parent_id IS NOT NULL\n" +
                                                      "AND od.version = " + version + " \n" +
                                                      "AND od.visit_type = " + visitType + " \n" +
                                                      "AND od.is_used = " + isUsed + " \n" +
                                                      "AND ddb.version = " + version + " \n" +
                                                      "AND ddb.visit_type = " + visitType + " \n" +
                                                      "AND ddb.is_used = " + isUsed + " \n" +
                                                      "GROUP BY ddb.officer_id\n" +
                                                      "ORDER BY count, ddb.officer_id ASC\n";
                            List<Map<String, Object>> coutList = baseDao.getAllByCondition(countOfficerBizz);

                            if (coutList == null || coutList.size() ==0) { // 每个员工都没有任务
                                officerId = officerIdList.get((int) Math.random() * officerIdList.size());
                            }

                            if (coutList != null && coutList.size() == officerIdList.size()) { // 每个员工都有任务
                                officerId = (String) coutList.get((int) Math.random() * coutList.size()).get("officerId");
                            }

                            if (coutList != null && coutList.size() < officerIdList.size() && coutList.size() != 0) { // 有员工没有任务
                                List<String> officerIdBizzList = new ArrayList<String>(); // 有任务办事人员id集合
                                for (Map<String, Object> officerMap: coutList) {
                                    String officerIdAll = (String) officerMap.get("officerId");
                                    officerIdBizzList.add(officerIdAll); // 集中工作人员id
                                }

                                // 去除可以接收预约的员工Id集合中的有任务的员工id
                                officerIdList1 = new ArrayList<>(officerIdList); // 副本
                                officerIdList1.removeAll(officerIdBizzList);
                                officerIdList = officerIdList1;

                                // 判断剩余员工id集合数量
                                if (officerIdList.size() == 1) { // 只有一个
                                    officerId = officerIdList.get(0);
                                }

                                if (officerIdList.size() > 1) { // 有多个
                                    officerId = officerIdList.get(1);
                                }
                            }
                        }
                    }
                }

                // 经过分析计算之后，如果offcerId = null
                if (officerId == null || "".equals(officerId)) {
                    if (allOfficerDep != null && allOfficerDep.size() >0) {
                        Map<String, Object> officerId1 = allOfficerDep.get((int) Math.random() * allOfficerDep.size());
                        officerId = (String) officerId1.get("officerId");
                    }
                }

                // 将居民预约信息存入bespeak表中
                String insertBespakSql = "INSERT INTO \n" +
                                             "\tbespeak(\n" +
                                             "\t\tID,\n" +
                                             "\t\ttime,\n" +
                                             "\t\tdweller_id,\n" +
                                             "\t\tdep_id,\n" +
                                             "\t\tbizz_id,\n" +
                                             "\t\tofficer_id,\n" +
                                             "\t\tis_socity_bizz,\n" +
                                             "\t\tbizz_type,\n" +
                                             "\t\tcreate_time,\n" +
                                             "\t\tstamp,\n" +
                                             "\t\tversion,\n" +
                                             "\t\tvisit_plat,\n" +
                                             "\t\tvisit_type,\n" +
                                             "\t\tis_used\n" +
                                             "\t) \n" +
                                         "VALUES(\n" +
                                             "\t\t'" + bespeakId + "',\n" +
                                             "\t\t'" + appointmentTime + "',\n" +
                                             "\t\t'" + dwellerId + "',\n" +
                                             "\t\t'" + depId + "',\n" +
                                             "\t\t'" + bizzId + "',\n" +
                                             "\t\t'" + officerId + "',\n" +
                                             "\t\t" + isSocityBizz + ",\n" +
                                             "\t\t" + bizzType + ",\n" +
                                             "\t\t'" + createTime + "',\n" +
                                             "\t\t'" + stamp + "',\n" +
                                             "\t\t" + version + ",\n" +
                                             "\t\t" + visitPlat + ",\n" +
                                             "\t\t" + visitType + ",\n" +
                                             "\t\t" + isUsed + "\n" +
                                             "\t)";
                int update = baseDao.update(insertBespakSql);
                if (update < 1) {
                    logger.info("添加预约信息失败");
                    map = ResultMap.creatReault("77", "失败", "数据库操作失败");
                    logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }

                // 查询该居民预约的日期那天排在第几位
                String countBespeakSql = "SELECT\n" +
                                            "\tCOUNT(*) count\n" +
                                         "FROM\n" +
                                            "\tbespeak bs\n" +
                                         "WHERE\n" +
                                            "\tbs.time = '" + appointmentTime + "'\n" +
                                         "AND bs.create_time <= '" + createTime + "'\n" +
                                         "AND bs.version = " + version + "\n" +
                                         "AND bs.visit_type = " + visitType + "\n" +
                                         "AND bs.is_used = " + isUsed + "\n" +
                                         "ORDER BY\n" +
                                            "\tbs.time,\n" +
                                            "\tbs.create_time";
                Long count = baseDao.getCount(countBespeakSql);

                map = ResultMap.creatReault("0", "成功", "预约成功");
                map.put("index", count); // 预约日期当天排在第几位
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("98", "失败", "参数类型错误");
            logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
            return map;
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            return map;
        }

        logger.info("出去《网页和微信小程序 - 业务预约》appointment()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 获取用户详细信息
     * @param param 加密后的信息
     * @return 结果集
     */
    public LinkedHashMap<Object, Object> queryUserInfo(String param, HttpServletRequest request){
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                String code = (String)jsonObject.get("code");
                String session_key = null;

                logger.info("根据code向微信服务器请求的地址：" + String.format(WechartCommon.GET_USER_INFO_URL, WechartCommon.APPID, WechartCommon.SECRET, code));
                // 向微信服务器发送Https请求，根据临时登录code获取用户信息
                String resultJson = VisitUrl.sendHttps(String.format(WechartCommon.GET_USER_INFO_URL, WechartCommon.APPID, WechartCommon.SECRET, code), null);

                // 解析返回的json结果
                JSONObject jsonObject1 = JSON.parseObject(resultJson);
                if(jsonObject != null){
                    Object errcode = jsonObject.get("errcode");
                    if (errcode != null) { // 发送错误，code无效
                        logger.error("通过临时登录code：" + code + " 获取用户信息失败。errcode：" + errcode + "，errmsg：" + jsonObject.get("errmsg"));
                        return null;
                    } else { // 获取信息成功
                        session_key =  (String)jsonObject1.get("session_key"); // 用户 session_key
                    }
                }

                // 获取相关数据
                String signature = (String)jsonObject.get("signature");
                String rawData = (String)jsonObject.get("rawData");
                String encryptedData = (String)jsonObject.get("encryptedData");
                String iv = (String)jsonObject.get("iv");

                // 验证签名，保证数据的完整性
                boolean b = SignatureUtil.checkSignature(signature, rawData, session_key);
                if (!b){
                    logger.info("验证签名失败，数据不完整");
                    map = ResultMap.creatReault("2", "验证签名失败", null);
                    return map;
                }

                // 验证签名成功，解密敏感数据
                String userInfo = decrypt(WechartCommon.APPID, encryptedData, session_key, iv);
                if (userInfo == null) {
                    logger.info("获取用户信息失败");
                    map = ResultMap.creatReault("2", "获取用户信息失败", null);
                    return map;
                }

                // TODO 小程序 - 获取微信用户信息
                // 将用户的信息出入缓存中
                // 在用户进行预约的时候在取出来跟居民关联到一起

                map = ResultMap.creatReault("0", "成功", null);
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("1", "失败", "参数为空");
            }
        } catch (IOException e) {
            logger.info("向微信服务器发送请求失败异常：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        }

        logger.info("出去《微信小程序 - 获取用户信息》getUserInfo()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 发送模板消息
     * @param param 包含form_id等信息
     * @return 结果集 - 发送成功或者失败
     */
    public Object sendTemplateMessage(String param){

        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isEmpty(StringUtils.trim(param))){
                // test
                // 测试封装json格式字符串数据
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                jsonMap.put("form_id", "FORMID"); // 表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id

                // test
                param = JSON.toJSONString(jsonMap);
                logger.info("测试param：" + param);

                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                String FORMID = (String)jsonObject.get("form_id");

                // 发送模板消息
                // 1.封装测试模板数据
                Map<String, Object> templateMap = new HashMap<String, Object>();
                templateMap.put("touser", "OPENID"); // 接收者（用户）的 openid
                templateMap.put("template_id", "TEMPLATE_ID"); // 所需下发的模板消息的id
                templateMap.put("page", "index"); // 点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转
                templateMap.put("form_id", FORMID); // 表单提交场景下，为 submit 事件带上的 formId；支付场景下，为本次支付的 prepay_id

                // 2.拼接模板内容
                Map<String, Object> dataMap = new HashMap<String, Object>();
                dataMap.put("keyword1", new HashMap<String, Object>().put("value", "339208499"));
                dataMap.put("keyword2", new HashMap<String, Object>().put("value", "2015年01月05日 12:30"));
                dataMap.put("keyword3", new HashMap<String, Object>().put("value", "粤海喜来登酒店"));
                dataMap.put("keyword4", new HashMap<String, Object>().put("value", "广州市天河区天河路208号"));

                templateMap.put("data", dataMap); // 模板内容，不填则下发空模板
                templateMap.put("color", "color"); // 模板内容字体的颜色，不填默认黑色 【废弃】
                templateMap.put("emphasis_keyword", "keyword1.DATA"); // 模板需要放大的关键词，不填则默认无放大

                // 3.将封装的模板消息封装成一个json字符串
                String templateStr = JSON.toJSONString(jsonMap);

                // TODO 小程序 - 从redis中取出wechartToken
                Jedis jedis = new Jedis("140.143.210.101",6379);
                jedis.auth("q1w2e3r4t5");
                String wechartToken = jedis.get("wechartToken");

                logger.info("模板内容：" + templateStr);
                logger.info("发送模板地址：" +WechartCommon.SEND_TEMPLATE_MESSAGE_URL + wechartToken);
                // 4.向微信服务器发送Https请求，根据临时登录code获取用户信息
                String resultJson = VisitUrl.sendHttps(WechartCommon.SEND_TEMPLATE_MESSAGE_URL + wechartToken, templateStr);

                int flag = 1; // 不成功

                // 5.解析微信返回的json结果
                if (resultJson != null) {
                    JSONObject resultJsonObject = JSON.parseObject(param);
                    switch ((Integer) resultJsonObject.get("errcode")) {
                        case 0:
                            logger.info("模板消息发送成功");
                            flag = 0;
                            break;
                        case 40037:
                            logger.info("template_id不正确");
                            break;
                        case 41028:
                            logger.info("form_id不正确，或者过期");
                            break;
                        case 41029:
                            logger.info("form_id已被使用");
                            break;
                        case 41030:
                            logger.info("page不正确");
                            break;
                        case 45009:
                            logger.info("接口调用超过限额（目前默认每个帐号日调用限额为100万）");
                            break;
                        default:
                            break;
                    }
                }

                if (flag == 1) {
                    // 获取用户信息失败
                    logger.info("模板消息发送失败");
                    map = ResultMap.creatReault("2", "模板消息发送失败", null);
                } else {
                    map = ResultMap.creatReault("0", "成功", null);
                }
            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("1", "失败", "参数为空");
            }
        } catch (IOException e) {
            logger.info("向微信服务器发送请求失败异常：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        }

        logger.info("出去《微信小程序 - 发送模板消息》sendTemplateMessage()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 微信小程序 - 下载
     * @param request 请求
     * @param response 响应
     * @return 结果集 - 是否成功
     */
    public LinkedHashMap<Object,Object> download(HttpServletRequest request, HttpServletResponse response) {
        LinkedHashMap<Object, Object> map = null;
        try {
            // test
            // 测试封装json格式字符串数据
            Map<String, Object> jsonMap = new HashMap<String, Object>();
//            jsonMap.put("fileName1", "1 - 副本.jpg");
//            jsonMap.put("fileName2", "1.jpg");
            jsonMap.put("fileName", "2.zip");

            String param = JSON.toJSONString(jsonMap);
            logger.info("测试参数param：" + param);

            // 解析参数
            JSONObject paramJson = JSON.parseObject(param);
//            List<String> fileNameList = new ArrayList<>();
//            String fileName1 = (String)paramJson.get("fileName1");
//            String fileName2 = (String)paramJson.get("fileName2");
            String fileName = (String)paramJson.get("fileName");

//            fileNameList.add(fileName1);
//            fileNameList.add(fileName2);
//            for (String fileName : fileNameList) {
                // 编码 - 设置响应头
                // Header中只支持ASCII，传输的文件名必须是ASCII。iso-8859-1是单字节编码，向下兼容ASCII
                String fileNameResponse = new String(fileName.getBytes(),"iso-8859-1");
                logger.info("第二次文件名为:"+fileName);

                if (fileName == null || "".equals(StringUtils.trim(fileName))){
                    logger.info("文件名为空");
                    map = ResultMap.creatReault("1", "失败", "文件名为空");
                    return map;
                }

                // 设置响应头
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename=" + fileNameResponse);

                byte[] buff = new byte[1024];
                BufferedInputStream bis = null;
                OutputStream os = null;
                try {
                    os = response.getOutputStream();
                    bis = new BufferedInputStream(new FileInputStream(new File("C://" + fileName)));
                    int i = bis.read(buff);
                    while (i != -1) {
                        os.write(buff, 0, buff.length);
                        os.flush();
                        i = bis.read(buff);
                    }

                    logger.info("下载成功");
                    map = ResultMap.creatReault("0", "成功", "下载成功");
                } catch (IOException e) {
                    logger.info("文件异常：" + ExceptionDetailMessage.getExceptionDetail(e));
                    map = ResultMap.creatReault("99", "失败", "后台处理异常");
                    return map;
                } finally {
                    if (bis != null) {
                        try {
                            bis.close();
                        } catch (IOException e) {
                            logger.info("关闭流异常" + ExceptionDetailMessage.getExceptionDetail(e));
                            map = ResultMap.creatReault("99", "失败", "后台处理异常");
                            return map;
                        }
                    }
                }
//            }
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            return map;
        }

        logger.info("出去《微信小程序 - 文件下载》download()方法；出参 = " + JSON.toJSONString(map));
        return null;
    }

    /**
     * 微信小程序 - 上传
     * @param param 参数
     * @param request 请求
     * @param response 响应
     * @return 结果集 - 上传结果
     */
    public Object upload(String param, HttpServletRequest request, HttpServletResponse response) {
        LinkedHashMap<Object, Object> map = null;
        try {
            StandardMultipartHttpServletRequest req = (StandardMultipartHttpServletRequest) request;
            Iterator<String> iterator = req.getFileNames();

            if (!iterator.hasNext()) {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
                logger.info("出去《网页端和微信小程序 - 文件上传》upload()方法；出参 = " + JSON.toJSONString(map));
                return map;
            }

            String qiniuPath = null;
            List<String> canDownUrlList = new ArrayList<String>(); // 上传之后的可下载Url
            while (iterator.hasNext()) {
                HashMap<String, Object> res = new HashMap<String, Object>();
                MultipartFile file = req.getFile(iterator.next());
                FileInputStream fileInputStream = (FileInputStream)file.getInputStream(); // 文件流

                // 获取原始文件名
                String fileNames = file.getOriginalFilename();
                int split = fileNames.lastIndexOf(".");
                // 获取上传文件的后缀
                String extName = fileNames.substring(split + 1, fileNames.length());
                // 声明UUID
                String uuid = UUID.randomUUID().toString().replace("-", "");
                // 组成新的图片名称
                String newName = uuid + "." + extName;
                FileOutputStream out = new FileOutputStream(newName);
                //设置缓冲区
                byte[] buffer=new byte[1024];
                //输入流读入缓冲区，输出流从缓冲区写出
                while((fileInputStream.read(buffer))>0)
                {
                    out.write(buffer);
                }
                out.close();

                // 调用七牛上传
                QiNiu qiNiu = new QiNiu("O1mwgsXsFvpJO7F_G9Lc1KAWi60JYUp8LyD6CyNm", "2yF2OzZthjAsyQuKpw5_KdDUU3Xp5lNpq_Dj0cOS", "kdzy", "https://res.kdzydev.cn");
                QiNiu.Result upload = qiNiu.upload( new FileInputStream(new File(newName)), newName);
                if (upload.isError()) {
                    qiniuPath = upload.getUrl();
                    logger.info("七牛上传成功后返回地址：" + qiniuPath);

                    // 获取可下载的路径
                    String downUrl = qiNiu.getDownUrl(qiniuPath, 3600 * 24 * 365 * 10);
                    String substring = null;

                    if (StringUtils.equals("0",param)) { // 网页端
                        substring =  downUrl;
                    } else {
//                        substring = downUrl.substring(22);
                        substring = downUrl;
                    }

//                    downUrl = "http://res.kdzydev.cn/";
                    canDownUrlList.add(downUrl);

                    new File(newName).delete();
                } else{
                    logger.info("上传失败");
                    map = ResultMap.creatReault("1", "失败", "上传失败");
                    logger.info("出去《网页端和微信小程序 - 文件上传》upload()方法；出参 = " + JSON.toJSONString(map));
                    return map;
                }
            }

            // 设置映射路径
            map = ResultMap.creatReault("0", "成功", "上传成功");
            map.put("canDownUrl", canDownUrlList);
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
            logger.info("出去《网页端和微信小程序 - 文件上传》upload()方法；出参 = " + JSON.toJSONString(map));
            return map;
        }

        logger.info("出去《网页端和微信小程序 - 文件上传》upload()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 网页端和微信小程序 - 获取居民注册（认证）信息
     * @param param 包含居民id等信息
     * @return 结果集
     */
    public Object getDwellerInfo(String param, HttpServletRequest request) {
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer version = jsonObject.getInteger("version"); // 版本 0:测试 1:生产
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否有效 0:有效 1:无效

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (version == null) {
                    logger.info("参数version为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }

                String systoken = null;
                if (visitPlat == 0) { // 网页端
                    systoken = (String)jsonObject.get("systoken"); // 全局token
                    if (StringUtils.isBlank(systoken)) {
                        logger.info("systoken为空");
                        return ResultMap.creatReault("33", "失败", "token为空");
                    }
                }

                String dwellerId = null;
                String dwellerIdcard = null;
                if (visitPlat == 0) { // 网页端 - 根据systoken换取居民id

                    // 根据身份证从redis中获取token
                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                    jedis.auth("q1w2e3r4t5");

                    List<String> infoList = jedis.hmget(systoken, "systoken",  "dwellerIdcard", "dwellerId");
                    String systokenRedis = null;
                    if (infoList != null && infoList.size() > 0) {
                        systokenRedis = infoList.get(0); // token
                        dwellerIdcard = infoList.get(1); // 居民身份证号
                        dwellerId = infoList.get(2); // 居民唯一标识
                    }

                    // 查看token是否过期
                    if (StringUtils.isBlank(systokenRedis)) { // 重新登录，弹出登录框
                        logger.info("全局systoken过期，需要重新获取systoken");
                        return ResultMap.creatReault("33", "失败", "systoken过期");
                    }

                    // token不一致
                    if (!StringUtils.equals(systokenRedis, systoken)) {
                        logger.info("用户访问的token不一致");
                        return ResultMap.creatReault("331", "失败", "systoken不一致");
                    }
                }

                if (visitPlat == 2) { // 小程序 - 根据key_code_openid换取openid -> 在查询dwellerId居民id

                    String keyCodeOpenid = (String)jsonObject.get("key_code_openid"); // 换取openid
                    if (StringUtils.isBlank(StringUtils.trim(keyCodeOpenid))) {
                        logger.info("参数visit_type为空");
                        return ResultMap.creatReault("88", "失败", "参数为空");
                    }

                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                    jedis.auth("q1w2e3r4t5");
                    String openId = jedis.get(keyCodeOpenid);

                    // 根据openid查询出居民Id
                    String queryDwellerId = "SELECT\n" +
                                                "\td.ID dwellerId,\n" +
                                                "\td.dweller_name dwellerName,\n" +
                                                "\td.dweller_idcard dwellerIdcard,\n" +
                                                "\td.telphone dwellerTelphone,\n" +
                                                "\td.check_flag checkFlag\n" +
                                            "FROM\n" +
                                                "\tdweller d,\n" +
                                                "\tdweller_wechat dw\n" +
                                            "WHERE\n" +
                                                "\td.ID = dw.dweller_id\n" +
                                            "AND dw.openid = '" + openId + "'\n" +
                                            "AND d.version = " + version + "\n" +
                                            "AND d.visit_type = " + visitType + "\n" +
                                            "AND d.is_used = " + isUsed + "\n" +
                                            "AND dw.version = " + version + "\n" +
                                            "AND dw.visit_type = " + visitType + "\n" +
                                            "AND dw.is_used = " + isUsed + "\n" +
                                            "GROUP BY dw.dweller_id";
                    List<Map<String, Object>> dwellerIdList = baseDao.getAllByCondition(queryDwellerId);
                    if (dwellerIdList == null || dwellerIdList.size() <= 0) {
                        logger.info("微信没有关联居民信息");
                        return ResultMap.creatReault("332", "失败", "微信没有关联居民信息");
                    }

                    dwellerId = (String) dwellerIdList.get(0).get("dwellerId"); // 居民id
                }

                // 根据居民id查询信息
                String dwellerInfoSql = "SELECT\n" +
                                            "\tdw.ID dwellerId,\n" +
                                            "\tdw.dweller_name dwellerName,\n" +
                                            "\tdw.dweller_idcard dwellerIdcard,\n" +
                                            "\tdw.telphone dwellerTelphone,\n" +
                                            "\tdw.check_flag checkFlag\n" +
                                        "FROM\n" +
                                            "\tdweller dw\n" +
                                        "WHERE\n" +
                                            "\tdw.ID = '" + dwellerId + "'\n" +
                                        "AND dw.version = " + version + "\n" +
                                        "AND dw.visit_type = " + visitType + "\n" +
                                        "AND dw.is_used = " + isUsed + "\n" +
                                        "GROUP BY dw.update_time DESC";

                List<Map<String, Object>> dwellerInfoList = baseDao.getAllByCondition(dwellerInfoSql);

                if (dwellerInfoList == null || dwellerInfoList.size() == 0) { // 用户信息查询失败
                    logger.info("结果集为空");
                    return ResultMap.creatReault("1", "成功", "结果集为空");
                }

                if (dwellerInfoList != null && dwellerInfoList.size() > 0) {
                    logger.info("查询居民信息成功：" + dwellerId);
                    return ResultMap.creatReault("0", "成功", dwellerInfoList.get(0));
                }

            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            return ResultMap.creatReault("98", "失败", "参数类型错误");
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        }

        logger.info("出去《网页端和微信小程序 - 获取居民注册（认证）信息》getDwellerInfo()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

    /**
     * 网页端 - 登出
     * @param param 包含居民id，systoken等信息
     * @return 结果集 - 成功或者失败
     */
    public Object logout(String param, HttpServletRequest request) {
        LinkedHashMap<Object, Object> map = null;
        try {
            if (StringUtils.isNoneBlank(StringUtils.trim(param))){
                // 1.解析json数据
                JSONObject jsonObject = JSON.parseObject(param);
                Long stamp = jsonObject.getLong("stamp"); // 时间戳
                Integer version = jsonObject.getInteger("version"); // 版本 0:测试 1:生产
                Integer visitType = jsonObject.getInteger("visit_type"); // 访问类型 0:测试 1:生产
                Integer visitPlat = jsonObject.getInteger("visit_plat"); // 访问平台 0:网页 1:一体机 2:小程序 3:其他
                Integer isUsed = jsonObject.getInteger("is_used"); // 是否有效 0:有效 1:无效

                // 参数非空判断
                if (stamp == null) {
                    logger.info("参数stamp为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (version == null) {
                    logger.info("参数version为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (isUsed == null) {
                    logger.info("参数is_used为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (visitPlat == null) {
                    logger.info("参数visit_plat为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }
                if (visitType == null) {
                    logger.info("参数visit_type为空");
                    return ResultMap.creatReault("88", "失败", "参数为空");
                }

                String systoken = null;
                if (visitPlat == 0) { // 网页端
                    systoken = (String)jsonObject.get("systoken"); // 全局token
                    if (StringUtils.isBlank(systoken)) {
                        logger.info("systoken为空");
                        return ResultMap.creatReault("33", "失败", "token为空");
                    }
                }

                if (visitPlat == 0) { // 网页端 - 根据systoken换取居民id

                    // 根据身份证从redis中获取token
                    Jedis jedis = new Jedis("140.143.210.101", 6379);
                    jedis.auth("q1w2e3r4t5");

                    List<String> infoList = jedis.hmget(systoken, "systoken",  "dwellerIdcard", "dwellerId");
                    String systokenRedis = null;
                    if (infoList != null && infoList.size() > 0) {
                        systokenRedis = infoList.get(0); // token
                    }

                    // 查看token是否过期
                    if (StringUtils.isBlank(systokenRedis)) { // 重新登录，弹出登录框
                        logger.info("全局systoken过期，需要重新获取systoken");
                        return ResultMap.creatReault("33", "失败", "systoken过期");
                    }

                    // token不一致
                    if (!StringUtils.equals(systokenRedis, systoken)) {
                        logger.info("用户访问的token不一致");
                        return ResultMap.creatReault("331", "失败", "systoken不一致");
                    }

                    // 一致 - 将redis中的systoken清除
                    Long del = jedis.del(systoken);
                    if (del <= 0) {
                        logger.info("登出失败");
                        return ResultMap.creatReault("1", "失败", "登出失败");
                    }
                    if (del > 0) {
                        logger.info("登出成功");
                        map = ResultMap.creatReault("0", "成功", "登出成功");
                    }
                    jedis.close();
                }

            } else {
                logger.info("参数为空");
                map = ResultMap.creatReault("88", "失败", "参数为空");
            }
        } catch (ClassCastException e) {
            logger.info("后台处理异常，异常信息1：" + ExceptionDetailMessage.getExceptionDetail(e));
            return ResultMap.creatReault("98", "失败", "参数类型错误");
        } catch (Exception e) {
            logger.info("后台处理异常，异常信息：" + ExceptionDetailMessage.getExceptionDetail(e));
            map = ResultMap.creatReault("99", "失败", "后台处理异常");
        }

        logger.info("出去《网页端和微信小程序 - 获取居民注册（认证）信息》getDwellerInfo()方法；出参 = " + JSON.toJSONString(map));
        return map;
    }

}
